﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using IllusionUtility.GetUtility;
using RootMotion;
using RootMotion.FinalIK;
using Studio;
using UnityEngine;

namespace WzhAddon
{
	public class DefaultCharaAnimOverride : MonoBehaviour
	{
		private bool defaultAnimeEnabled = true;
		public MonoBehaviour currentController;
		public OCIChar studioChara;
		public ChaControl charInfo;
		public Transform cx_N_k_t;
		public Transform cx_N_height;
		public List<Action> postLateUpdateListeners = new List<Action>();
		public Action OnDrivingRigControllerDisabled;
		private Dictionary<object, Transform> defaultIKTargets = new Dictionary<object, Transform>();
		private bool _moveBustDynamicBoneAfterIK;
		private static MethodInfo m_DynamicBoneLateUpdate = typeof(DynamicBone_Ver02).GetMethod("LateUpdate", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod);
		private bool bustDynamicBoneCalculated;
		public static MethodInfo m_IKLateUpdate = typeof(SolverManager).GetMethod("LateUpdate", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod);
		public static MethodInfo m_IKUpdate = typeof(SolverManager).GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod);
		public static MethodInfo m_IKFixedUpdate = typeof(SolverManager).GetMethod("FixedUpdate", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod);
		private CharReference.RefObjKey[] AP_Ref_Keys = new CharReference.RefObjKey[]
		{
			(CharReference.RefObjKey)2,
				(CharReference.RefObjKey)3,
				(CharReference.RefObjKey)4,
				(CharReference.RefObjKey)5,
				(CharReference.RefObjKey)6,
				(CharReference.RefObjKey)7,
				(CharReference.RefObjKey)8,
				(CharReference.RefObjKey)9,
				(CharReference.RefObjKey)10,
				(CharReference.RefObjKey)11,
				(CharReference.RefObjKey)12,
				(CharReference.RefObjKey)13,
				(CharReference.RefObjKey)14,
				(CharReference.RefObjKey)15,
				(CharReference.RefObjKey)16,
				(CharReference.RefObjKey)17,
				(CharReference.RefObjKey)18,
				(CharReference.RefObjKey)19,
				(CharReference.RefObjKey)20,
				(CharReference.RefObjKey)21,
				(CharReference.RefObjKey)22,
				(CharReference.RefObjKey)23,
				(CharReference.RefObjKey)24,
				(CharReference.RefObjKey)25,
				(CharReference.RefObjKey)26,
				(CharReference.RefObjKey)27,
				(CharReference.RefObjKey)28,
				(CharReference.RefObjKey)29,
				(CharReference.RefObjKey)30
		};
		private Dictionary<CharReference.RefObjKey, Vector3> defaultAPPos;
		private Dictionary<CharReference.RefObjKey, Quaternion> defaultAPRot;
		public bool DefaultAnimeEnabled { get { return this.defaultAnimeEnabled; } }
		public Animator defaultAnimator { get { return this.charInfo.animBody; } }
		public bool moveBustDynamicBoneAfterIK
		{
			get { return this._moveBustDynamicBoneAfterIK; }
			set
			{
				if (this._moveBustDynamicBoneAfterIK == value) return;
				this._moveBustDynamicBoneAfterIK = value;
				if (!value) this.ResetBreastAnimeDynamicBoneState();
			}
		}

		public static DefaultCharaAnimOverride Get(OCIChar studioChara)
		{
			ChaControl chaControl = studioChara.charInfo;
			if (chaControl == null) return null;
			DefaultCharaAnimOverride defaultCharaAnimOverride = chaControl.gameObject.GetComponent<DefaultCharaAnimOverride>();
			if (defaultCharaAnimOverride == null)
			{
				defaultCharaAnimOverride = chaControl.gameObject.AddComponent<DefaultCharaAnimOverride>();
				defaultCharaAnimOverride.Init(studioChara, chaControl);
			}
			return defaultCharaAnimOverride;
		}

		public void Init(OCIChar studioChara, ChaControl charInfo)
		{
			this.studioChara = studioChara;
			this.charInfo = charInfo;
			if (charInfo.sex == 1)
			{
				this.cx_N_k_t = TransformFindEx.FindLoop(charInfo.animBody.transform, "cf_N_k").transform;
				this.cx_N_height = TransformFindEx.FindLoop(charInfo.objBodyBone.transform, "cf_N_height").transform;
			}
			else
			{
				this.cx_N_k_t = TransformFindEx.FindLoop(charInfo.animBody.transform, "cm_N_k").transform;
				this.cx_N_height = TransformFindEx.FindLoop(charInfo.objBodyBone.transform, "cm_N_height").transform;
			}
			base.StartCoroutine(this.DisableDefaultAnimIKCo());
			if (charInfo.sex == 1)
			{
				base.StartCoroutine(this.MoveBustDynamicBoneControlCo());
			}
			this.SaveAPPoints();
		}
		public void RestoreDefaultIKTargets()
		{
			try
			{
				FullBodyBipedIK fullBodyIK = this.studioChara.fullBodyIK;
				Dictionary<OIIKTargetInfo, Transform> dictionary = new Dictionary<OIIKTargetInfo, Transform>();
				foreach (OCIChar.IKInfo ikinfo in this.studioChara.listIKTarget)
				{
					dictionary[ikinfo.targetInfo] = ikinfo.targetObject;
				}
				fullBodyIK.solver.bodyEffector.target = dictionary[this.studioChara.oiCharInfo.ikTarget[0]];
				fullBodyIK.solver.leftShoulderEffector.target = dictionary[this.studioChara.oiCharInfo.ikTarget[1]];
				fullBodyIK.solver.leftArmChain.bendConstraint.bendGoal = dictionary[this.studioChara.oiCharInfo.ikTarget[2]];
				fullBodyIK.solver.leftHandEffector.target = dictionary[this.studioChara.oiCharInfo.ikTarget[3]];
				fullBodyIK.solver.rightShoulderEffector.target = dictionary[this.studioChara.oiCharInfo.ikTarget[4]];
				fullBodyIK.solver.rightArmChain.bendConstraint.bendGoal = dictionary[this.studioChara.oiCharInfo.ikTarget[5]];
				fullBodyIK.solver.rightHandEffector.target = dictionary[this.studioChara.oiCharInfo.ikTarget[6]];
				fullBodyIK.solver.leftThighEffector.target = dictionary[this.studioChara.oiCharInfo.ikTarget[7]];
				fullBodyIK.solver.leftLegChain.bendConstraint.bendGoal = dictionary[this.studioChara.oiCharInfo.ikTarget[8]];
				fullBodyIK.solver.leftFootEffector.target = dictionary[this.studioChara.oiCharInfo.ikTarget[9]];
				fullBodyIK.solver.rightThighEffector.target = dictionary[this.studioChara.oiCharInfo.ikTarget[10]];
				fullBodyIK.solver.rightLegChain.bendConstraint.bendGoal = dictionary[this.studioChara.oiCharInfo.ikTarget[11]];
				fullBodyIK.solver.rightFootEffector.target = dictionary[this.studioChara.oiCharInfo.ikTarget[12]];
				for (int i = 0; i < 5; i++)
				{
					OIBoneInfo.BoneGroup boneGroup = (OIBoneInfo.BoneGroup)(1 << i);
					this.studioChara.ActiveIK(boneGroup, this.studioChara.oiCharInfo.activeIK[i] & this.studioChara.oiCharInfo.enableIK, false);
				}
			}
			catch (Exception arg)
			{
				Console.WriteLine("Ov: " + arg);
			}
		}

		private IEnumerator DisableDefaultAnimIKCo()
		{
			for (; ; )
			{
				yield return null;
				this.DisableEnableDefaultAnim();
			}
			//yield break;
		}

		private IEnumerator MoveNeckControllerCo()
		{
			for (; ; )
			{
				yield return new WaitForEndOfFrame();
				this.MoveNeckController();
			}
			//yield break;
		}

		public void DisableEnableDefaultAnim()
		{
			if (!base.gameObject) return;
			if (!this.defaultAnimeEnabled)
			{
				this.charInfo.animBody.enabled = false;
				return;
			}
			this.cx_N_height.localPosition = Vector3.zero;
			this.cx_N_height.localRotation = Quaternion.identity;
			this.cx_N_k_t.localRotation = Quaternion.identity;
			this.charInfo.animBody.enabled = true;
		}

		private void MoveNeckController() { }
		public void Aquire(MonoBehaviour controller)
		{
			if (this.defaultAnimeEnabled == false) return;
			this.defaultAnimeEnabled = false;
			this.currentController = controller;
			this.DisableEnableDefaultAnim();
		}

		public void Release(MonoBehaviour controller)
		{
			if (!this.defaultAnimeEnabled && controller == this.currentController)
			{
				this.defaultAnimeEnabled = true;
				this.currentController = null;
				this.DisableEnableDefaultAnim();
				this.OnDrivingRigControllerDisabled = null;
			}
		}

		public void IKUpdate()
		{
			if (!this.defaultAnimeEnabled)
			{
				DefaultCharaAnimOverride.m_IKUpdate.Invoke(this.studioChara.fullBodyIK, new object[0]);
			}
		}

		public void IKLateUpdate()
		{
			if (!this.defaultAnimeEnabled)
			{
				DefaultCharaAnimOverride.m_IKLateUpdate.Invoke(this.studioChara.fullBodyIK, new object[0]);
				if (this.IsIKEnabled() && this.DefaultAnimeEnabled && this.moveBustDynamicBoneAfterIK)
				{
					this.CalculateBreastDynamicBone();
					this.bustDynamicBoneCalculated = true;
				}
			}
		}

		public void IKFixedUpdate()
		{
			if (!this.defaultAnimeEnabled)
			{
				DefaultCharaAnimOverride.m_IKFixedUpdate.Invoke(this.studioChara.fullBodyIK, new object[0]);
			}
		}

		public void DoPostLateUpdate()
		{
			foreach (Action action in this.postLateUpdateListeners)
			{
				try
				{
					action();
				}
				catch (Exception)
				{
				}
			}
		}

		public void ResetBoneRotations(bool resetFemaleBust = false)
		{
			string str = charInfo.sex == 0 ? "cm" : "cf";
			Vector3 localPosition = charInfo.sex == 0 ? new Vector3(0f, 1.1435f, -0.018f) : new Vector3(0f, 1.1435f, 0f);
			this.cx_N_height.localPosition = Vector3.zero;
			this.cx_N_height.localRotation = Quaternion.identity;
			GameObject gameObject = TransformFindEx.FindLoop(this.charInfo.objBodyBone.transform, str + "_J_Hips");
			gameObject.transform.localPosition = localPosition;
			gameObject.transform.localRotation = Quaternion.identity;
			Transform transform = this.charInfo.objBodyBone.transform;
			for (int i = 0; i < transform.childCount; i++)
			{
				this.InitializeBasePositions(transform.GetChild(i), resetFemaleBust);
			}
		}
		private void InitializeBasePositions(Transform t, bool resetFemaleBust = false)
		{
			if (t.name.StartsWith("cf_J_sk_") || t.name.Contains("_J_Head_s")) return;
			if (t.name == "Sphere") return;
			if (t.name == "Driving Rig") return;
			if (t.name.StartsWith("N_")) return;
			if (!resetFemaleBust && t.name.Contains("_J_Mune00")) return;
			t.localRotation = Quaternion.identity;
			for (int i = 0; i < t.childCount; i++)
			{
				this.InitializeBasePositions(t.GetChild(i), false);
			}
		}
		public void ReleaseIKTargets() { }
		// Token: 0x060004C0 RID: 1216 RVA: 0x00024E3C File Offset: 0x0002303C
		private IEnumerator MoveBustDynamicBoneControlCo()
		{
			if (this.charInfo.sex == 0)
			{
				yield break;
			}
			Female female = this.charInfo.human as Female;
			Body femaleBody = female.body;
			for (; ; )
			{
				yield return null;
				if (this.DefaultAnimeEnabled && this.moveBustDynamicBoneAfterIK)
				{
					if (femaleBody.bustDynamicBone_L.enabled) femaleBody.bustDynamicBone_L.enabled = false;
					if (femaleBody.bustDynamicBone_R.enabled) femaleBody.bustDynamicBone_R.enabled = false;
					if (this.charInfo.animBody.layerCount > 2) this.charInfo.animBody.SetLayerWeight(1, 0f);
				}
				yield return new WaitForEndOfFrame();
				if (this.DefaultAnimeEnabled)
				{
					bool moveBustDynamicBoneAfterIK = this.moveBustDynamicBoneAfterIK;
				}
				this.bustDynamicBoneCalculated = false;
			}
			//yield break;
		}
		public void DisableBreastDynamicBoneAndAnime()
		{
			if (this.charInfo.sex == 0) return;
			Body body = (this.charInfo.human as Female).body;
			body.bustDynamicBone_L.enabled = false;
			body.bustDynamicBone_R.enabled = false;
			if (this.charInfo.animBody.layerCount > 2)
			{
				this.charInfo.animBody.SetLayerWeight(1, 0f);
			}
		}
		private void LateUpdate()
		{
			if (this.DefaultAnimeEnabled && this.moveBustDynamicBoneAfterIK)
			{
				DefaultCharaAnimOverride.m_IKLateUpdate.Invoke(this.studioChara.fullBodyIK, new object[0]);
			}
		}
		public void CalculateBreastDynamicBone()
		{
			if (this.bustDynamicBoneCalculated) return;
			this.bustDynamicBoneCalculated = true;
			if (this.charInfo.sex == 1)
			{
				Body body = (this.charInfo.human as Female).body;
				DynamicBone_Ver02 bustDynamicBone_L = body.bustDynamicBone_L;
				DynamicBone_Ver02 bustDynamicBone_R = body.bustDynamicBone_R;
				DefaultCharaAnimOverride.m_DynamicBoneLateUpdate.Invoke(bustDynamicBone_L, new object[0]);
				DefaultCharaAnimOverride.m_DynamicBoneLateUpdate.Invoke(bustDynamicBone_R, new object[0]);
			}
		}

		public void ResetBreastAnimeDynamicBoneState()
		{
			if (this.charInfo.sex == 1)
			{
				this.charInfo.PlayDynamicBoneBust(0, true);
				this.charInfo.PlayDynamicBoneBust((SEXY.CharDefine.DynamicBoneKind)1, true);
			}
		}
		private void SaveAPPoints()
		{
			this.defaultAPPos = new Dictionary<CharReference.RefObjKey, Vector3>();
			this.defaultAPRot = new Dictionary<CharReference.RefObjKey, Quaternion>();
			foreach (CharReference.RefObjKey refObjKey in this.AP_Ref_Keys)
			{
				GameObject referenceInfo = this.charInfo.GetReferenceInfo(refObjKey);
				if (referenceInfo != null)
				{
					this.defaultAPPos[refObjKey] = referenceInfo.transform.localPosition;
					this.defaultAPRot[refObjKey] = referenceInfo.transform.localRotation;
				}
			}
		}
		public void ResetAPPoints()
		{
			foreach (CharReference.RefObjKey refObjKey in this.AP_Ref_Keys)
			{
				GameObject referenceInfo = this.charInfo.GetReferenceInfo(refObjKey);
				if (referenceInfo != null)
				{
					if (this.defaultAPPos.ContainsKey(refObjKey))
					{
						referenceInfo.transform.localPosition = this.defaultAPPos[refObjKey];
						referenceInfo.transform.localRotation = this.defaultAPRot[refObjKey];
					}
					else
					{
						Debug.Log("AP Ref: " + refObjKey + " not found.");
					}
				}
			}
		}

		public bool IsIKEnabled()
		{
			return this.studioChara.oiCharInfo.enableIK;
		}
	
	}
}
